package com.drelephant.commons.sdk;

import com.drelephant.commons.Verify;
import com.drelephant.commons.req.BaseChannelReq;
import com.drelephant.commons.util.AESUtils;
import com.drelephant.commons.util.BeanUtil;
import com.drelephant.commons.util.RSAUtils;
import org.apache.commons.codec.digest.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author wenshuai@hz-health.cn
 */

public enum VerifyTypeEnum implements Verify {

    /**
     * MD5签名
     */
    MD5 {
        @Override
        public BaseChannelReq<?> encrypt(String appKey, Object reqData, String pubKey, String appPriKey) throws VerifyException {
            try {
                BaseChannelReq<Object> channelReq = new BaseChannelReq<>(appKey, reqData);
                Map<String, Object> map = BeanUtil.beanToMap(reqData);
                map.put("reqNo", channelReq.getReqNo());
                map.put("reqTime", channelReq.getReqTime());
                String signValue = BeanUtil.getSortKeyValueParam(map);
                String sign = DigestUtils.md5Hex((signValue + appPriKey).getBytes(StandardCharsets.UTF_8));
                channelReq.setSign(sign);
                return channelReq;
            } catch (Exception e) {
                throw new VerifyException("签名失败", e);
            }

        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T decrypt(BaseChannelReq<?> channelReq, Class<T> clazz, String appPubKey, String priKey) throws VerifyException {
            try {
                Map<String, Object> map = BeanUtil.beanToMap(channelReq.getReqData());
                map.put("reqNo", channelReq.getReqNo());
                map.put("reqTime", channelReq.getReqTime());
                String signValue = BeanUtil.getSortKeyValueParam(map);
                String sign = DigestUtils.md5Hex((signValue + appPubKey).getBytes(StandardCharsets.UTF_8));
                if (!sign.equals(channelReq.getSign())) {
                    throw new VerifyException("签名验证失败");
                }
                return (T) channelReq.getReqData();
            } catch (Exception e) {
                throw new VerifyException("签名验证失败",e);
            }
        }
    },

    /**
     * RSA签名
     */
    RSA {
        @Override
        public BaseChannelReq<?> encrypt(String appKey, Object reqData, String pubKey, String appPriKey) throws VerifyException {
            try {
                BaseChannelReq<Object> channelReq = new BaseChannelReq<>(appKey, reqData);
                Map<String, Object> map = BeanUtil.beanToMap(reqData);
                map.put("reqNo", channelReq.getReqNo());
                map.put("reqTime", channelReq.getReqTime());
                String sign = RSAUtils.sign(map, appPriKey);
                channelReq.setSign(sign);
                return channelReq;
            } catch (Exception e) {
                throw new VerifyException("签名失败", e);
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T decrypt(BaseChannelReq<?> channelReq, Class<T> clazz, String appPubKey, String priKey) throws VerifyException {
            try {
                Map<String, Object> map = BeanUtil.beanToMap(channelReq.getReqData());
                map.put("reqNo", channelReq.getReqNo());
                map.put("reqTime", channelReq.getReqTime());
                if (!RSAUtils.verify(map, appPubKey, channelReq.getSign())) {
                    throw new VerifyException("签名验证失败");
                }
                return (T) channelReq.getReqData();
            } catch (Exception e) {
                throw new VerifyException("签名验证失败", e);
            }
        }
    },
    /**
     * AES加密RSA签名
     */
    AES_RSA {
        @Override
        public BaseChannelReq<?> encrypt(String appKey, Object reqData, String pubKey, String appPriKey) throws VerifyException {
            try {
                // 将原始请求对象格式化成JSON字符串
                String plainMessageBody = BeanUtil.toJsonString(reqData);
                // 进行AES加密
                AESUtils.EncryptResult aesEncrypt = AESUtils.encrypt(plainMessageBody);
                // AES加密后的参数
                String encryptData = aesEncrypt.getCipherText();
                // 把AES KEY 通过对方RSA PublicKey进行加密
                String encryptKey = RSAUtils.encryptByPublicKey(aesEncrypt.getKey(), pubKey);
                // 把AES IV 通过对方RSA PublicKey进行加密
                String encryptSalt = RSAUtils.encryptByPublicKey(aesEncrypt.getSalt(), pubKey);
                // 构建请求对象
                BaseChannelReq<String> channelReq = new BaseChannelReq<>(appKey,encryptData);
                channelReq.setKey(encryptKey);
                channelReq.setSalt(encryptSalt);
                // 将请求对象 通过己方RSA PrivateKey进行摘要签名
                String sign = RSAUtils.sign(BeanUtil.beanToMap(channelReq), appPriKey);
                channelReq.setSign(sign);
                return channelReq;
            } catch (Exception e) {
                throw new VerifyException("加密加签失败", e);
            }
        }

        @Override
        public <T> T decrypt(BaseChannelReq<?> channelReq, Class<T> clazz, String appPubKey, String priKey) throws VerifyException {
            try {
                //公钥验签
                if (RSAUtils.verify(BeanUtil.beanToMap(channelReq), appPubKey, channelReq.getSign())) {
                    //私钥解密
                    String key = new String(RSAUtils.decryptByPrivateKey(channelReq.getKey(), priKey));
                    String salt = new String(RSAUtils.decryptByPrivateKey(channelReq.getSalt(), priKey));
                    String data = AESUtils.decrypt(key, channelReq.getReqData().toString(), salt);
                    return BeanUtil.parseObject(data, clazz);
                } else {
                    throw new VerifyException("签名验证失败");
                }
            } catch (Exception e) {
                throw new VerifyException("解密验签失败", e);
            }
        }
    },
    /**
     * 不需要加密验签
     */
    NOT_NEED_VERIFY {
        @Override
        public BaseChannelReq<?> encrypt(String appKey, Object reqData, String pubKey, String appPriKey) throws VerifyException {
            BaseChannelReq<Object> channelReq = new BaseChannelReq<>();
            channelReq.setAppKey(appKey);
            channelReq.setReqData(reqData);
            return channelReq;
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T decrypt(BaseChannelReq<?> channelReq, Class<T> clazz, String appPubKey, String priKey) throws VerifyException {
            return (T) channelReq.getReqData();
        }
    };

    VerifyTypeEnum() {
    }

}
